package com.arrogames.blondbattle.game
{
	import ash.core.Engine;
	import ash.core.Entity;
	import com.arrogames.blondbattle.game.graphics.BaseExplosionView;
	import com.arrogames.blondbattle.game.movement.Dimension;
	import com.arrogames.blondbattle.game.purchases.Cooldown;
	import com.arrogames.blondbattle.game.combat.Damage;
	import com.arrogames.blondbattle.game.rendering.Camera;
	import com.arrogames.blondbattle.game.rendering.Display;
	import com.arrogames.blondbattle.game.combat.Faction;
	import com.arrogames.blondbattle.game.state.Crown;
	import com.arrogames.blondbattle.game.state.GameState;
	import com.arrogames.blondbattle.game.combat.Health;
	import com.arrogames.blondbattle.game.combat.Missile;
	import com.arrogames.blondbattle.game.state.Money;
	import com.arrogames.blondbattle.game.movement.Motion;
	import com.arrogames.blondbattle.game.purchases.NewUnit;
	import com.arrogames.blondbattle.game.purchases.Order;
	import com.arrogames.blondbattle.game.movement.Position;
	import com.arrogames.blondbattle.game.combat.Range;
	import com.arrogames.blondbattle.game.combat.Reload;
	import com.arrogames.blondbattle.game.purchases.Reward;
	import com.arrogames.blondbattle.game.movement.Spawner;
	import com.arrogames.blondbattle.game.movement.Speed;
	import com.arrogames.blondbattle.game.combat.Target;
	import com.arrogames.blondbattle.game.combat.Unit;
	import com.arrogames.blondbattle.game.purchases.Costs;
	import com.arrogames.blondbattle.game.combat.Weapon;
	import com.arrogames.blondbattle.game.graphics.AsteroidView;
	import com.arrogames.blondbattle.game.graphics.BackgroundView;
	import com.arrogames.blondbattle.game.graphics.BaseView;
	import com.arrogames.blondbattle.game.graphics.ExplosionView;
	import com.arrogames.blondbattle.game.graphics.GroundView;
	import com.arrogames.blondbattle.game.graphics.HitIndicatorView;
	import com.arrogames.blondbattle.game.graphics.SpawnFlag;
	import com.arrogames.blondbattle.game.graphics.UnitView;
	import com.arrogames.blondbattle.model.UnitDefinition;
	import com.arrogames.blondbattle.model.WeaponDefinition;
	import com.arrogames.blondbattle.ui.buttons.MusicButton;
	import com.greensock.OverwriteManager;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import org.as3commons.logging.api.getLogger;
	import org.as3commons.logging.api.ILogger;
	import starling.display.DisplayObject;
	import starling.display.Image;
	import starling.textures.Texture;
	import starling.events.Event;
	
	

	public class EntityCreator
	{
		private static const logger:ILogger = getLogger(EntityCreator);
		
		private var engine : Engine;
		
		public function EntityCreator( engine : Engine )
		{
			this.engine = engine;
		}
		
		public function destroyEntity( entity : Entity ) : void
		{
			engine.removeEntity( entity );
		}
		
		public function createGame() : Entity
		{
			var gameEntity : Entity = new Entity()
				.add( new GameState() );
			engine.addEntity( gameEntity );
			return gameEntity;
		}

		public function createBackground(width:Number) : Entity
		{
			var backgroundView:BackgroundView = new BackgroundView(width);
			var background:Entity = new Entity()
				.add( new Display(backgroundView) )
				.add( new Position ( 0, 0, 0) );
			engine.addEntity(background);
			return background;
		}
		
		
		/**
		 * Create a ground entity and add it to the engine
		 * @param	x		Number
		 * @param	y		Number
		 * @param	width	Number
		 * @param	height	Number
		 * @return			Entity
		 */
		public function createGround( width:Number, height:Number, x:Number, y:Number) : Entity
		{
			var ground:Entity = new Entity()
				.add ( new Position( x, y, 0 ) )
				.add ( new Display( new GroundView( width, height) ) );
			engine.addEntity( ground );
			return ground;
		}
		
		/**
		 * Create a base entity and add it to the engine
		 * @param	height	Number	the height of the base in pixels
		 * @param	x		Number
		 * @param	y		Number
		 * @return			Entity
		 */
		public function createBase( x:Number, y:Number, faction:Faction, health:Number) : Entity
		{
			var healthComponent:Health = new Health ( health );
			
			var baseView:BaseView = new BaseView ( healthComponent );
			var base: Entity = new Entity()
				.add ( new Position( x, y, 0 ) )
				.add ( new Display ( baseView ) )
				.add ( new Dimension (baseView.width, baseView.height) ) 
				.add ( healthComponent )
				.add ( faction )
				.add ( new Reward( 100 ) )
				.add ( new Crown( ) );
			engine.addEntity( base );
			return base;
		}
		
		/**
		 * Create a unit and place it on the battlefield with the given position, speed and rotation
		 * 
		 * @param	x			Number
		 * @param	y			Number
		 * @param	xSpeed		Number
		 * @param	ySpeed		Number
		 * @param	rotation	Number
		 */
		public function createUnit(unitDefinition:UnitDefinition, faction:Faction):Entity
		{
			var health:Health = new Health ( unitDefinition.health);
			
			var unitView:UnitView = new UnitView(unitDefinition.textureName, faction.name, health);
			var weapon:Entity = createWeapon(unitDefinition.weapon);
			var motion:Motion = new Motion ( unitDefinition.speed, 0, 0, 0 );
			logger.debug('creating ' + unitDefinition.name + ' with speed: ' + unitDefinition.speed + ", motion: "+ motion.velocity);
			
			var unit:Entity = new Entity()
				.add( new Display ( unitView ) )
				.add( new Dimension(unitView.width, unitView.height) )
				.add( faction )
				.add( new Weapon( weapon ) )
				.add( health )
				.add( new Reward ( unitDefinition.costs) )
				.add( new Costs ( unitDefinition.costs) )
				.add( new NewUnit (unitDefinition) );
			engine.addEntity(unit);
			return unit;
		}
		
		
		private function createWeapon(weapon:WeaponDefinition):Entity {
			var entity:Entity = new Entity()
				.add( new Range ( weapon.range) )
				.add( new Damage (weapon.damage) )
				.add( new Reload ( weapon.reload) )
				.add( new Speed ( weapon.speed) );
			engine.addEntity(entity);
			return entity;
		}
		
		/**
		 * Create a missile and place it on the battlefield with the given postition, speed and rotation
		 * @param	x
		 * @param	y
		 * @param	xSpeed
		 * @param	ySpeed
		 * @param	rotation
		 * @param	damage
		 * @return	Entity
		 */
		public function createMissile( x:Number, y:Number, xSpeed:Number, ySpeed:Number, rotation:Number, damage:Number, range:Number, faction:Faction) : Entity
		{
			var missileView:AsteroidView = new AsteroidView(5);
			var missile:Entity = new Entity()
				.add( new Position (x, y, rotation) )
				.add( new Motion (xSpeed, ySpeed, 0, 0) )
				.add( new Missile (damage, 60) )
				.add( new Display (missileView) )
				.add( new Range (range) )
				.add( faction );
			engine.addEntity(missile);
			return missile;
		}
		
		/**
		 * Create an explosion at the given position
		 * 
		 * @param	x
		 * @param	y
		 * @return	Entity
		 */
		public function createExplosion(position:Position, baseExplosion:Boolean = false) : Entity
		{
			var explosionView:DisplayObject = null;
			if (baseExplosion) {
				explosionView = new BaseExplosionView("explosion");
			} else {
				explosionView = new ExplosionView("explosion");
			}
			var explosion:Entity = new Entity()
				.add( position )
				.add( new Display( explosionView ) );
			engine.addEntity(explosion);
			return explosion;
		}
		
		public function createHitIndator(position:Position, label:String) : Entity
		{
			var hitIndicatorView:HitIndicatorView = new HitIndicatorView(label);
			var hitIndicator:Entity = new Entity()
				.add( position )
				.add( new Motion(0, -40, 0, 0) )
				.add( new Display(hitIndicatorView));
			engine.addEntity(hitIndicator);
			return hitIndicator;
		}
		
		public function createSpawner( x:Number, y:Number, faction:Faction):Entity {
			
			var spawnFlag:SpawnFlag = new SpawnFlag(faction.name);
			
			var spawner:Entity = new Entity()
				.add(new Position(x, y, 0))
				.add(new Spawner(faction.name))
				.add(faction)
				
			engine.addEntity(spawner);
			return spawner;
		}
		
		public function createCommander(money:Number, faction:Faction):Entity {
			var entity:Entity = new Entity()
				.add(new Money(money))
				.add(faction);
				
			engine.addEntity(entity);
			return entity;
		}
		
		public function createUnitOrder(unit:UnitDefinition, faction:Faction):Entity {
			var entity:Entity = new Entity()
				.add(new Order(unit))
				.add(new Unit(unit.name))
				.add(faction);
				
			engine.addEntity(entity);
			return entity;
		}
		
		public function createCooldown(unit:Unit, duration:Number, faction:Faction):Entity{
			var entity:Entity = new Entity()
				.add(new Cooldown(duration))
				.add(unit)
				.add(faction);
				
			engine.addEntity(entity);
			return entity;
		}
		
		public function createCamera(viewport:Rectangle):Entity {
			var entity:Entity = new Entity()
				.add(new Camera(viewport))
				.add(new Position(0,0,0) )
				.add(new Motion(0,0,0, 0) );
				
			engine.addEntity(entity);
			return entity;
		}
	}
}
